﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.Configuration;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
using ParkingLot.Entitys.Enums;
using ParkingLot.Entitys.Messages;
using ParkingLot.Utility.Compare;
using ParkingLot.Utility.Extend;
using ParkingLot.Utility.LogHelps;
using ParkingLot.Utility.SocketHelp;

namespace ParkingLot.Utility.MessageHelp
{

    /*设计模式之单例模式和代理人模式 
    内部消息通信 MessageAggregator 和UDPReceive报文通信互相不认识。
    此时通过MessageManage作为代理人
    此处用单例比静态类合适
    广播：服务器向所有进程发送       服务器作为发送方
    组播：任意进程向服务器发送       服务器作为接收方
        */

    /// <summary>
    /// 消息管理类    
    /// </summary>
    public class MessageManage : DispatcherObject
    {
        #region 字段

        #region 去重判断字段

        private bool m_IsStartQueuq;

        /// <summary>
        /// 是否启动广播
        /// </summary>
        private bool m_IsStartAirringCast;

        /// <summary>
        /// 是否启动了组播
        /// </summary>
        private bool m_IsStartGroupCast;


        #endregion

        /// <summary>
        /// 广播服务器IP
        /// </summary>
        public  string ServerToClientIP;

        /// <summary>
        /// 广播服务器端口号 
        /// </summary>
        public  int ServerToClientPort;

        /// <summary>
        /// 组播服务器IP
        /// </summary>
        public  string ClientToServerIP;

        /// <summary>
        /// 组播服务器端口号
        /// </summary>
        public  int ClientToServerPort;

        /// <summary>
        /// 内部标识
        /// </summary>
        public  byte[] MessageMark;

        /// <summary>
        /// 类的Guid和他的方法
        /// </summary>
        public Dictionary<Guid, MethodInfo> DcitMethodInfos = new Dictionary<Guid, MethodInfo>();

        /// <summary>
        /// 缓存推送的对象序列化之后的流
        /// </summary>
        private ConcurrentQueue<byte[]> m_CacheBytes = new ConcurrentQueue<byte[]>();

        private Task m_Task;

        /// <summary>
        /// 去重用的码 16位的GUID
        /// </summary>
        //private static List<byte[]> m_LisBytes = new List<byte[]>();

        /// <summary>
        /// 去重用的码 16位的GUID (这里)
        /// </summary>
        private static Dictionary<Guid,object> m_DictBytes = new Dictionary<Guid, object>(20000);
        #endregion

        #region 单例模式

        private static object m_Locker = new object();

        private MessageManage()
        {
            try
            {

                // 广播服务器IP
                ServerToClientIP = ConfigManager.AppSettings["ServerToClientIP"].Value;

                // 广播服务器端口号 
                ServerToClientPort = int.Parse(ConfigManager.AppSettings["ServerToClientPort"].Value);

                // 组播服务器IP
                ClientToServerIP = ConfigManager.AppSettings["ClientToServerIP"].Value;

                // 组播服务器端口号
                ClientToServerPort = int.Parse(ConfigManager.AppSettings["ClientToServerPort"].Value);

                //内部标识
                MessageMark = Guid.Parse(ConfigManager.AppSettings["MessageMark"].Value).ToByteArray();

                //写日志记录初始化成功
                LogHelp.AddLog(new LogEncity()
                {
                    LogTime = DateTime.MaxValue.GetCurTime(),
                    LogType = LogType.Init,
                    Message = Warning.Instance.MessageManageInitWarn,
                });
            }
            catch (Exception exception)
            {
                LogHelp.AddLog(new LogEncity(Warning.Instance.MessageManageWarn, exception));
            }
        }

        private static MessageManage m_Instance = null;

        public static MessageManage Instance
        {
            get
            {
                if (m_Instance == null)
                {
                    lock (m_Locker)
                    {
                        if (m_Instance == null)
                        {
                            m_Instance = new MessageManage();
                        }
                    }
                }
                return m_Instance;
            }
        }

        #endregion


        /// <summary>
        /// 
        /// </summary>
        /// <param name="serverToClientIP">服务器到客户端IP</param>
        /// <param name="serverToClientPort">服务器到客户端端口号</param>
        /// <param name="clientToServerIP">客户端到服务器IP</param>
        /// <param name="clientToServerPort">客户端到服务器端口号</param>
        /// <param name="messageMark">区分外部报文的标识</param>
        public void Init(string serverToClientIP,int serverToClientPort,string clientToServerIP,int clientToServerPort, Guid messageMark)
        {
            try
            {
                // 广播服务器IP
                ServerToClientIP = serverToClientIP;

                // 广播服务器端口号 
                ServerToClientPort = serverToClientPort;

                // 组播服务器IP
                ClientToServerIP = clientToServerIP;

                // 组播服务器端口号
                ClientToServerPort = clientToServerPort;

                //内部标识
                MessageMark = messageMark.ToByteArray();

                //写日志记录初始化成功
                LogHelp.AddLog(new LogEncity()
                {
                    LogTime = DateTime.MaxValue.GetCurTime(),
                    LogType = LogType.Init,
                    Message = Warning.Instance.MessageManageInitWarn,
                });
            }
            catch (Exception exception)
            {
                LogHelp.AddLog(new LogEncity(Warning.Instance.MessageManageWarn, exception));
            }
        }


        /// <summary>
        /// 根据不同类型启动不同接收线程
        /// </summary>
        /// <param name="udpCommunication"></param>
        public void StartReceive(UdpCommunication udpCommunication, UDPReceiveHelp udpReceiveHelp)
        {
            try
            {
                //客户端接受服务端
                if ((udpCommunication & UdpCommunication.AirringCast) == UdpCommunication.AirringCast)
                {
                    if (!m_IsStartAirringCast)
                    {
                        StartReceive(udpReceiveHelp);
                        m_IsStartAirringCast = true;

                        //写日志记录初始化成功
                        LogHelp.AddLog(new LogEncity()
                        {
                            LogType = LogType.Init,
                            Message = Warning.Instance.ClientToServerInitWarn
                        });
                    }
                }
            }
            catch (Exception exception)
            {
                LogHelp.AddLog(new LogEncity(Warning.Instance.ClientToServerInitErrorWarn, exception));
            }

            try
            {
                //服务端接收客户端
                if ((udpCommunication & UdpCommunication.GroupCast) == UdpCommunication.GroupCast)
                {
                    if (!m_IsStartGroupCast)
                    {
                        StartReceive(udpReceiveHelp);
                        //去重操作
                        m_IsStartGroupCast = true;

                        //写日志记录初始化成功
                        LogHelp.AddLog(new LogEncity()
                        {
                            LogType = LogType.Init,
                            Message = Warning.Instance.ServerToClientInitWarn
                        });
                    }
                }
            }
            catch (Exception exception)
            {
                //写日志记录初始化失败
                LogHelp.AddLog(new LogEncity(Warning.Instance.ServerToClientInitErrorWarn,exception));
                
            }
           
        }

        private void StartReceive(UDPReceiveHelp udpReceiveHelp)
        {
            udpReceiveHelp.ReceivedPacket += this.AddBytes;
            udpReceiveHelp.Start();
            if (m_IsStartQueuq == false)
            {
                StartQueue();
                m_IsStartQueuq = true;
            }
        }

        /// <summary>
        /// 开启接收处理线程
        /// </summary>
        private void StartQueue()
        {
            if (m_IsStartQueuq)
            {
                return;
            }

            m_Task = new Task(QueueAction, TaskCreationOptions.LongRunning);
            m_Task.Start();

        }

        private void QueueAction()
        {
            LogHelp.AddLog(new LogEncity()
            {
                LogType = LogType.Init,
                Message = "开启处理网络消息线程成功"
            });
            while (true)
            {
                try
                {
                    #region 获取值
                    if (m_CacheBytes.Count == 0)
                    {
                        Thread.Sleep(100);
                        continue;
                    }

                    byte[] bytes;
                    bool bolGetValue = m_CacheBytes.TryDequeue(out bytes);
                    if ((!bolGetValue) || (bytes == null))
                    {
                        continue;
                    }
                    #endregion

                    byte[] seralizeBytes;
                    bool bolHaveDeal = GetBytes(bytes, out seralizeBytes);
                    if (!bolHaveDeal)
                    {
                        #region 取值做运算
                        new Task(() =>
                        {
                            DealMessageAction(seralizeBytes);
                        }).Start();
                        #endregion
                    }
                }
                catch (Exception exception)
                {
                    LogHelps.LogHelp.AddLog(new LogEncity()
                    {
                        LogTime = DateTime.MinValue.GetCurTime(),
                        Message = $"{Warning.Instance.QueueActionWarn}{exception.Message}{exception.StackTrace}",
                        LogType = LogType.Error
                    });
                }

            }
        }

        /// <summary>
        /// 为类序列化后的流加  报文头操作 解密等操作
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static bool GetBytes(byte[] bytes, out byte[] seralizeBytes)
        {
            bool result;
            int headLength = 32;
            seralizeBytes = new byte[bytes.Length - headLength];
            byte[] headBytes = new byte[16];
            for (int i = 0; i < headBytes.Length; i++)
            {
                headBytes[i] = bytes[i + 16];
            }

            Guid messageIdGuid=new Guid(headBytes);
            ByteArrayCompare byteArrayCompare = new ByteArrayCompare();
            if (m_DictBytes.ContainsKey(messageIdGuid))
            {
                return true;
            }

            m_DictBytes.Add(messageIdGuid,null);

            if (m_DictBytes.Count >= 20000)
            {
               Guid firstGuid= m_DictBytes.ElementAt(0).Key;
                m_DictBytes.Remove(firstGuid);
            }

            for (int i = 0; i < seralizeBytes.Length; i++)
            {
                seralizeBytes[i] = bytes[i + headLength];
            }
            return false;
        }

        public byte[] GetHeadBytes()
        {
            //报文头=内部标识+本次标识
            byte[] thisTimeMarkBytes = Guid.NewGuid().ToByteArray();
            byte[] headBytes = new byte[thisTimeMarkBytes.Length + MessageMark.Length];
            //合并两个byte流
            Buffer.BlockCopy(MessageMark, 0, headBytes, 0, MessageMark.Length);//这种方法仅适用于字节数组
            Buffer.BlockCopy(thisTimeMarkBytes, 0, headBytes, MessageMark.Length, thisTimeMarkBytes.Length);

            return headBytes;
        }

        public byte[] GetHeadBytes(string strImageGuid)
        {
            //报文头=内部标识+本次标识
            Guid imageGuid;
            if (!Guid.TryParse(strImageGuid,out imageGuid))
            {
                imageGuid = Guid.NewGuid();
            }
            byte[] thisTimeMarkBytes = imageGuid.ToByteArray();
            byte[] headBytes = new byte[thisTimeMarkBytes.Length + MessageMark.Length];
            //合并两个byte流
            Buffer.BlockCopy(MessageMark, 0, headBytes, 0, MessageMark.Length);//这种方法仅适用于字节数组
            Buffer.BlockCopy(thisTimeMarkBytes, 0, headBytes, MessageMark.Length, thisTimeMarkBytes.Length);

            return headBytes;
        }

        public static void AddMethInfo(Guid guid, MethodInfo methodInfo)
        {

        }

        public static void RemoveMethInfo(Guid guid)
        {

        }

        private void AddBytes(byte[] bytes)
        {
            m_CacheBytes.Enqueue(bytes);
        }

        /// <summary>
        /// 执行Subrise的方法
        /// </summary>
        /// <param name="buff"></param>
        private void DealMessageAction(byte[] buff)
        {
            try
            {
                object obj = SerializeHelp.ByteFlowHelp.ByteToObj(buff);
                Guid guid = obj.GetType().GUID;
                if (DcitMethodInfos.ContainsKey(guid))
                {
                    //执行方法
                    DcitMethodInfos[guid].Invoke(null, new object[1] { obj });
                }
            }
            catch (Exception exception)
            {
                //写日志记录异常
                LogHelp.AddLog(new LogEncity()
                {
                    LogTime = DateTime.MinValue.GetCurTime(),
                    Message = $"{Warning.Instance.DealMessageActionWarn}{exception.Message}{exception.StackTrace}",
                    LogType = LogType.Error
                });
            }



        }
    }
}
